#pragma once

#include <iostream>
#include <string>
#include <memory>

namespace Protocol
{
    const std::string ProtSep = " ";
    const std::string LineBreakSep = "\n";

    // 添加报文
    // "len\nx op y\n" 加入\n，方便区分报文的完整性
    std::string Encode(const std::string &message)
    {
        std::string len = std::to_string(message.size());
        std::string package = len + LineBreakSep + message + LineBreakSep;
        return package;
    }

    // 解析报文
    //          获取的报文数据          解析报文获得的数据
    bool Decode(std::string &package, std::string *message)
    {
        // int total = GetLen(package);
        // if(package.size() < total)
        //     return false;

        auto pos = package.find(LineBreakSep);
        if (pos == std::string::npos)
            return false;
        std::string len = package.substr(0, pos);
        int messagelen = std::stoi(len);

        // 一个完整报文的大小
        int total = len.size() + messagelen + 2 * LineBreakSep.size();
        if (package.size() < total)
            return false;
        *message = package.substr(pos + LineBreakSep.size(), messagelen);
        std::cout << "inbufferstream: " << package << std::endl;

        package.erase(0, total);
        // std::cout << "inbufferstream: " << package << std::endl;

        return true;
    }

    // // 获取一个完整报文的长度
    // int GetLen(std::string &package)
    // {
    //     auto pos = package.find(LineBreakSep);
    //     if (pos == std::string::npos)
    //         return false;
    //     std::string len = package.substr(0, pos);
    //     int messagelen = std::stoi(len);

    //     // 一个完整报文的大小
    //     int total = len.size() + messagelen + 2 * LineBreakSep.size();
    //     return total;
    // }

    class Request
    {
    public:
        Request(int x = 0, int y = 0, char op = 0)
            : _data_x(x), _data_y(y), _oper(op)
        {
        }

        void Debug()
        {
            std::cout << "_data_x: " << _data_x << std::endl;
            std::cout << "_data_y: " << _data_y << std::endl;
            std::cout << "_oper: " << _oper << std::endl;
        }

        // 测试使用
        void Inc()
        {
            _data_x++;
            _data_y++;
        }

        // 序列化
        // 结构化数据->字符串
        bool Serialize(std::string *out)
        {
            *out = std::to_string(_data_x) + ProtSep + _oper + ProtSep + std::to_string(_data_y);
            return true;
        }

        // 反序列化
        // 字符串->结构化数据
        bool Deserialize(std::string &in)
        {
            auto left = in.find(ProtSep);
            if (left == std::string::npos)
                return false;
            auto right = in.rfind(ProtSep);
            if (right == std::string::npos)
                return false;

            _data_x = std::stoi(in.substr(0, left));
            _data_y = std::stoi(in.substr(right + ProtSep.size()));
            std::string oper = in.substr(left + ProtSep.size(), right - (left + ProtSep.size()));
            if (oper.size() != 1)
                return false;
            _oper = oper[0];
            return true; // 只有一个完整的报文才返回true
        }

        int GetX()
        {
            return _data_x;
        }

        int Gety()
        {
            return _data_y;
        }

        char GetOper()
        {
            return _oper;
        }

    private:
        // _data_x _oper _data_y
        // 报文的自描述字段
        // "len\nx op y\n" \n不属于报文的一部分，len为"x op y"的长度
        int _data_x; // 第一个参数
        int _data_y; // 第二个参数
        char _oper;  // + - * / %
    };

    class Response
    {
    public:
        Response(int result = 0, int code = 0)
            : _result(result), _code(code)
        {
        }

        // 序列化
        bool Serialize(std::string *out)
        {
            *out = std::to_string(_result) + ProtSep + std::to_string(_code);
            return true;
        }

        // 反序列化
        bool Deserialize(std::string &in)
        {
            auto pos = in.find(ProtSep);
            if (pos == std::string::npos)
                return false;
            _result = std::stoi(in.substr(0, pos));
            _code = std::stoi(in.substr(pos + ProtSep.size()));
            return true;
        }

        void SetResult(int result)
        {
            _result = result;
        }

        void SetCode(int code)
        {
            _code = code;
        }

        int GetResult() { return _result; };
        int GetCode() { return _code; };

    private:
        //"len\n_result _code\n"
        int _result;
        int _code;
    };

    // 工厂模式
    class Factory
    {
    public:
        std::shared_ptr<Request> BuildRequest()
        {
            std::shared_ptr<Request> req = std::make_shared<Request>();
            return req;
        }

        std::shared_ptr<Request> BuildRequest(int x, int y, char op)
        {
            std::shared_ptr<Request> req = std::make_shared<Request>(x, y, op);
            return req;
        }

        std::shared_ptr<Response> BuildResponse()
        {
            std::shared_ptr<Response> req = std::make_shared<Response>();
            return req;
        }

        std::shared_ptr<Response> BuildResponse(int result, int code)
        {
            std::shared_ptr<Response> req = std::make_shared<Response>(result, code);
            return req;
        }
    };
}